#ifndef __BLOCK_block_queueUEUE__
#define __BLOCK_block_queueUEUE__
#include <pthread.h>
#include <queue>

template<class T>
class BlockQueue
{
public:
    BlockQueue(int cap):_cap(cap), _productor_wait_num(0), _consumer_wait_num(0)
    {
        //条件变量初始化
        pthread_cond_init(&_productor_con, nullptr);
        pthread_cond_init(&_consumer_con, nullptr);
        //互斥量初始化
        pthread_mutex_init(&_mutex, nullptr);
    }
    void push(const T& val)   //生产者调用的接口
    {
        //加锁
        pthread_mutex_lock(&_mutex);
        
        /*开始访问阻塞队列(公共资源)*/
        
        while (isfull())   //阻塞队列满了就去条件变量下等待 while循环增强代码的健壮性：防止多个生产线程同时唤醒，但是阻塞队列只剩下一个空间
        {
            _productor_wait_num++;
            //wait前：持有锁 是安全的
            pthread_cond_wait(&_productor_con, &_mutex);    
            /*wait时，a.将当前进程添加到指定条件变量队列下  b.对当前进程进行解锁 c.返回时，重新竞争该锁 
            如果不解锁 消费者线程不能环形之*/
            
            //wait后：重新持有锁 是安全的
            //此时生产者线程已经唤醒
            _productor_wait_num--;
        }
        _block_queue.push(val);
         //通知消费者消费
         if (_consumer_wait_num > 0)
         {
             pthread_cond_signal(&_consumer_con);    //unlock前后都可以唤醒消费者 唤醒消费者，消费者会重新竞争锁
         }
        //解锁
        pthread_mutex_unlock(&_mutex);
    }
        
       
    void pop(T& val)    //消费者调用的接口
    {
          //加锁
        pthread_mutex_lock(&_mutex);
        
        /*开始访问阻塞队列(公共资源)*/
        
        while (isempty())   //阻塞队列空了就不消费 while循环防止多个消费者同时唤醒，但是只有一个有效数据
        {
            _consumer_wait_num++;
            pthread_cond_wait(&_consumer_con, &_mutex);    
            /*wait时，a.将当前进程添加到指定条件变量队列下  b.对当前进程进行解锁 c.返回时，重新竞争该锁 
            如果不解锁 消费者线程不能环形之*/
            
            //此时生产者线程已经唤醒
            _consumer_wait_num--;
        }
        //开始消费
        val = _block_queue.front();
        _block_queue.pop();
        //通知生产者生产
        if (_productor_wait_num > 0)
        {
            pthread_cond_signal(&_productor_con);
        }

        //解锁
        pthread_mutex_unlock(&_mutex);
    }
    bool isempty()
    {
        return _block_queue.empty();
    }
    bool isfull()
    {
        return _cap == _block_queue.size();
    }
    ~BlockQueue()
    {
        //释放条件变量
        pthread_cond_destroy(&_productor_con);
        pthread_cond_destroy(&_consumer_con);
        //释放互斥量
        pthread_mutex_destroy(&_mutex);
    }
private:
    //底层结构
    std::queue<T> _block_queue;
    int _cap;   //阻塞队列总容量
    //互斥量
    pthread_mutex_t _mutex;
    //条件变量
    pthread_cond_t _productor_con;   //生产者的条件变量
    pthread_cond_t _consumer_con;   //消费者的条件变量
    //处于条件变量下等待的线程个数
    int _productor_wait_num;        //生产线程的等待个数
    int _consumer_wait_num;         //消费线程的等待个数

};

#endif